<?php
class Set extends Object
{
	public static function Pluck($array, $key)
	{
		$output = array();
        foreach ($array as $value)
        {
            $output[] = $value[$key];
        }
        return $output;
	}

	public static function FindByKeys($array, $keys)
	{
		$output = array();
		foreach ($keys as $key)
		{
			if (array_key_exists($key, $array))
				$output[$key] = $array[$key];
		}
		return $output;
	}

	public static function Find($array, $field, $needle)
	{
		$output = array();
        foreach ($array as $key => $row)
            if (isset($row[$field]) && $row[$field] == $needle)
        	    $output[] = $key;
        return $output;
	}

    public static function FindOne($array, $field, $needle)
    {
        foreach ($array as $key => $row)
        {
            if (!is_array($row))
                throw new Exception('$row is not array');

            if (isset($row[$field]) && $row[$field] == $needle)
                return $key;
        }
        return null;
    }

	public static function Glue($glue, $array1, $array2)
	{
		$smaller = count($array1) < count($array2) ? $array1 : $array2;
		$output = array();
		foreach ($smaller as $key => $value)
			$output[$key] = $array1[$key] . $glue . $array2[$key];
		return $output;
	}

	public static function SelfCombine($array)
	{
		return array_combine($array, $array);
	}

	public static function Get($array, $path, $separator = '.')
	{
        if (is_object($array))
        {
            $getter = 'get'.ucfirst($path);
            return method_exists($array, $getter) ? $array->$getter() : $array->$path;
        }

		$fields = explode($separator, $path);
		foreach($fields as $field)
		{
            if (is_array($array) && array_key_exists($field, $array))
				$array = $array[$field];
            else if (is_object($array) && self::KeyExists($array, $field))
                $array = self::Get($array, $field);
			else
                return null;
		}
		return $array;
	}

	public static function KeyExists($array, $path)
	{
        if (is_object($array))
        {
            $reflect = new ReflectionObject($array);
            try
            {
                $prop = $reflect->getProperty($path);
                return $prop;
            }
            catch (Exception $ex)
            {
                $getter = 'get'.ucfirst($path);
                return method_exists($array, $getter);
            }
        }

		$fields = explode('.', $path);
		foreach($fields as $field)
		{
			if (is_array($array) && array_key_exists($field, $array))
				$array = $array[$field];
			else if (is_object($array) && self::KeyExists($array, $field))
                $array = self::Get($array, $field);
            else
				return false;
		}
		return true;
	}

	public static function Combine($array, $key, $value = null)
	{
		if (is_null($value)) $value = $key;
		$output = array();
		foreach($array as $item)
		{
            $i = Set::Get($item, $key);
            if (is_object($i)) $i = (string)$i;
            $output[$i] = Set::Get($item, $value);
		}
		return $output;
	}

	public static function RemovePath($array, $paths)
	{
		$path = array_shift($paths);
		if (isset($array[$path]))
		{
			if (count($paths) < 1)
				unset($array[$path]);
			else
				$array = self::RemovePath($array[$path]);
		}
		else if ($path == '{n}')
		{
			foreach($array as $key => $value)
			{
				$array[$key] = self::RemovePath($value, $paths);
			}
		}
		return $array;
	}

	public static function Remove($array, $path)
	{
		$paths = explode('.', $path);
		return self::RemovePath($array, $paths);
	}

    public static function First($array)
	{
		return array_shift($array);
	}

    public static function Excludes($excludes, $array)
	{
		$out = array();
		$excludes = String::ToArray($excludes);
        foreach ($array as $key => $value)
		{
			if (!in_array($key, $excludes))
				$out[$key] = $value;
		}
		return $out;
	}

    public static function Includes($includes, $array)
	{
		$out = array();
		$includes = String::ToArray($includes);
        foreach ($array as $key => $value)
		{
			if (in_array($key, $includes))
				$out[$key] = $value;
		}
		return $out;
	}

    public static function ToRecord($array, $field)
	{
		$out = array();
		foreach ($array as $value)
		{
			$out[][$field] = $value;
		}
		return $out;
	}

    public static function Shift($array, $count)
	{
        for($i=0;$i<$count;$i++)
        {
			array_shift($array);
		}
		return $array;
	}

    public static function AddItem($array)
    {
        $params = func_get_args();
        $add_items = Set::Shift($params, 1);
        foreach ($add_items as $key => $value)
        {
            if (!in_array($value, $array))
                $array[] = $value;
        }
        return $array;
    }

    public static function GetItem($array)
    {
        $params = func_get_args();
        $get_items = Set::Shift($params, 1);
        $result = array();
        foreach ($array as $key => $value)
        {
            if (in_array($value, $get_items))
                $result[] = $array[$key];
        }
        return $result;
    }

    public static function RemoveItem($array)
	{
		$params = func_get_args();
		$remove_items = Set::Shift($params, 1);
        foreach ($array as $key => $value)
		{
			if (in_array($value, $remove_items))
                unset($array[$key]);
		}
		return $array;
	}

    public static function Enclose($prefix, $array, $suffix)
    {
        return $prefix.implode($suffix.$prefix, $array).$suffix;
    }

    public static function Index($array, $key)
    {
        $out = array();
        foreach ($array as $value)
        {
            $out[$value[$key]] = $value;
        }
        return $out;
    }

    public static function Clones($array)
    {
        return $array;
    }

    public static function ReOrder($reorder, $array, $key_field, $order_field)
    {
        $sort = self::Combine($array, $key_field, $order_field);
        $sort[$reorder[$key_field]] = $reorder[$order_field]-0.5;
        asort($sort);
        $i = 1;
        foreach ($sort as $key => $value)
        {
            $item[$key_field] = $key;
            $item[$order_field] = $i++;
            $out[] = $item;
        }
        return $out;
    }
}
?>
